home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / ip / nfs / amd / amd-5.2 / config / mtab_file.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-06-23  |  8.6 KB  |  401 lines

  1. /*
  2.  * $Id: mtab_file.c,v 5.2 90/06/23 22:20:54 jsp Rel $
  3.  *
  4.  * Copyright (c) 1990 Jan-Simon Pendry
  5.  * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
  6.  * Copyright (c) 1990 The Regents of the University of California.
  7.  * All rights reserved.
  8.  *
  9.  * This code is derived from software contributed to Berkeley by
  10.  * Jan-Simon Pendry at Imperial College, London.
  11.  *
  12.  * Redistribution and use in source and binary forms are permitted provided
  13.  * that: (1) source distributions retain this entire copyright notice and
  14.  * comment, and (2) distributions including binaries display the following
  15.  * acknowledgement:  ``This product includes software developed by the
  16.  * University of California, Berkeley and its contributors'' in the
  17.  * documentation or other materials provided with the distribution and in
  18.  * all advertising materials mentioning features or use of this software.
  19.  * Neither the name of the University nor the names of its contributors may
  20.  * be used to endorse or promote products derived from this software without
  21.  * specific prior written permission.
  22.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  23.  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  24.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  25.  *
  26.  *    %W% (Berkeley) %G%
  27.  */
  28.  
  29. #include "am.h"
  30.  
  31. #ifdef READ_MTAB_FROM_FILE
  32.  
  33. #ifdef USE_FCNTL
  34. #include <fcntl.h>
  35. #else
  36. #include <sys/file.h>
  37. #endif /* USE_FCNTL */
  38.  
  39. #ifdef UPDATE_MTAB
  40.  
  41. /*
  42.  * Do strict /etc/mtab locking
  43.  */
  44. #define    MTAB_LOCKING
  45.  
  46. /*
  47.  * Firewall mtab entries
  48.  */
  49. #define    MTAB_STRIPNL
  50.  
  51. #include <sys/stat.h>
  52. static FILE *mnt_file;
  53.  
  54. /*
  55.  * If the system is being trashed by something, then
  56.  * opening mtab may fail with ENFILE.  So, go to sleep
  57.  * for a second and try again. (Yes - this has happened to me.)
  58.  *
  59.  * Note that this *may* block the automounter, oh well. 
  60.  * If we get to this state then things are badly wrong anyway...
  61.  *
  62.  * Give the system 10 seconds to recover but then give up.
  63.  * Hopefully something else will exit and free up some file
  64.  * table slots in that time.
  65.  */
  66. #define    NFILE_RETRIES    10 /* seconds */
  67.  
  68. #ifdef MTAB_LOCKING
  69. #ifdef LOCK_FCNTL
  70. static int lock(fd)
  71. {
  72.     int rc;
  73.     struct flock lk;
  74.  
  75.     lk.l_type = F_WRLCK;
  76.     lk.l_whence = 0;
  77.     lk.l_start = 0;
  78.     lk.l_len = 0;
  79.  
  80. again:
  81.     rc = fcntl(fd, F_SETLKW, (caddr_t) &lk);
  82.     if (rc < 0 && (errno == EACCES || errno == EAGAIN)) {
  83. #ifdef DEBUG
  84.         dlog("Blocked, trying to obtain exclusive mtab lock");
  85. #endif /* DEBUG */
  86.         sleep(1);
  87.         goto again;
  88.     }
  89.     return rc;
  90. }
  91. #else
  92. #define lock(fd) (flock((fd), LOCK_EX))
  93. #endif /* LOCK_FCNTL */
  94. #endif /* MTAB_LOCKING */
  95.  
  96. /*
  97.  * Unlock the mount table
  98.  */
  99. void unlock_mntlist()
  100. {
  101.     /*
  102.      * Release file lock, by closing the file
  103.      */
  104.     if (mnt_file) {
  105.         endmntent(mnt_file);
  106.         mnt_file = 0;
  107.     }
  108. }
  109.  
  110. /*
  111.  * Write out a mount list
  112.  */
  113. void rewrite_mtab(mp)
  114. mntlist *mp;
  115. {
  116.     FILE *mfp;
  117.  
  118.     /*
  119.      * Concoct a temporary name in the same
  120.      * directory as the target mount table
  121.      * so that rename() will work.
  122.      */
  123.     char tmpname[64];
  124.     int retries;
  125.     int tmpfd;
  126.     char *cp;
  127.     char *mcp = mtab;
  128.     cp = strrchr(mcp, '/');
  129.     if (cp) {
  130.         bcopy(mcp, tmpname, cp - mcp);
  131.         tmpname[cp-mcp] = '\0';
  132.     } else {
  133.         plog(XLOG_WARNING, "No '/' in mtab (%s), using \".\" as tmp directory", mtab);
  134.         tmpname[0] = '.'; tmpname[1] = '\0';
  135.     }
  136.     strcat(tmpname, "/mtabXXXXXX");
  137.     mktemp(tmpname);
  138.     retries = 0;
  139. enfile1:
  140.     if ((tmpfd = open(tmpname, O_RDWR|O_CREAT|O_TRUNC, 0644)) < 0) {
  141.         if (errno == ENFILE && retries++ < NFILE_RETRIES) {
  142.             sleep(1);
  143.             goto enfile1;
  144.         }
  145.         plog(XLOG_ERROR, "%s: open: %m", tmpname);
  146.         return;
  147.     }
  148.     if (close(tmpfd) < 0)
  149.         plog(XLOG_ERROR, "Couldn't close tmp file descriptor: %m");
  150.  
  151.     retries = 0;
  152. enfile2:
  153.     mfp = setmntent(tmpname, "w");
  154.     if (!mfp) {
  155.         if (errno == ENFILE && retries++ < NFILE_RETRIES) {
  156.             sleep(1);
  157.             goto enfile2;
  158.         }
  159.         plog(XLOG_ERROR, "setmntent(\"%s\", \"w\"): %m", tmpname);
  160.         return;
  161.     }
  162.  
  163.     while (mp) {
  164.         if (mp->mnt)
  165.             if (addmntent(mfp, mp->mnt))
  166.                 plog(XLOG_ERROR, "Can't write entry to %s", tmpname);
  167.         mp = mp->mnext;
  168.     }
  169.  
  170.     endmntent(mfp);
  171.  
  172.     /*
  173.      * Rename temporary mtab to real mtab
  174.      */
  175.     if (rename(tmpname, mtab) < 0)
  176.         plog(XLOG_ERROR, "rename %s to %s: %m", tmpname, mtab);
  177. }
  178.  
  179. #ifdef MTAB_STRIPNL
  180. static void mtab_stripnl(s)
  181. char *s;
  182. {
  183.     do {
  184.         s = strchr(s, '\n');
  185.         if (s)
  186.             *s++ = ' ';
  187.     } while (s);
  188. }
  189. #endif /* MTAB_STRIPNL */
  190.  
  191. /*
  192.  * Append a mntent structure to the
  193.  * current mount table.
  194.  */
  195. void write_mntent(mp)
  196. struct mntent *mp;
  197. {
  198.     int retries = 0;
  199.     FILE *mfp;
  200. enfile:
  201.     mfp = setmntent(mtab, "a");
  202.     if (mfp) {
  203. #ifdef MTAB_STRIPNL
  204.         mtab_stripnl(mp->mnt_opts);
  205. #endif /* MTAB_STRIPNL */
  206.         if (addmntent(mfp, mp))
  207.             plog(XLOG_ERROR, "Couldn't write %s: %m", mtab);
  208.         endmntent(mfp);
  209.     } else {
  210.         if (errno == ENFILE && retries < NFILE_RETRIES) {
  211.             sleep(1);
  212.             goto enfile;
  213.         }
  214.         plog(XLOG_ERROR, "setmntent(\"%s\", \"a\"): %m", mtab);
  215.     }
  216. }
  217.  
  218. #endif /* UPDATE_MTAB */
  219.  
  220. static struct mntent *mnt_dup(mp)
  221. struct mntent *mp;
  222. {
  223.     struct mntent *new_mp = ALLOC(mntent);
  224.  
  225.     new_mp->mnt_fsname = strdup(mp->mnt_fsname);
  226.     new_mp->mnt_dir = strdup(mp->mnt_dir);
  227.     new_mp->mnt_type = strdup(mp->mnt_type);
  228.     new_mp->mnt_opts = strdup(mp->mnt_opts);
  229.  
  230.     new_mp->mnt_freq = mp->mnt_freq;
  231.     new_mp->mnt_passno = mp->mnt_passno;
  232.  
  233.     return new_mp;
  234. }
  235.  
  236. /*
  237.  * Read a mount table into memory
  238.  */
  239. mntlist *read_mtab(fs)
  240. char *fs;
  241. {
  242.     mntlist **mpp, *mhp;
  243.  
  244.     struct mntent *mep;
  245.     FILE *mfp = 0;
  246.  
  247. #ifdef UPDATE_MTAB
  248.     /*
  249.      * There is a possible race condition if two processes enter
  250.      * this routine at the same time.  One will be blocked by the
  251.      * exclusive lock below (or by the shared lock in setmntent)
  252.      * and by the time the second process has the exclusive lock
  253.      * it will be on the wrong underlying object.  To check for this
  254.      * the mtab file is stat'ed before and after all the locking
  255.      * sequence, and if it is a different file then we assume that
  256.      * it may be the wrong file (only "may", since there is another
  257.      * race between the initial stat and the setmntent).
  258.      *
  259.      * Simpler solutions to this problem are invited...
  260.      */
  261.     int racing = 0;
  262. #ifdef MTAB_LOCKING
  263.     int rc;
  264.     int retries = 0;
  265.     struct stat st_before, st_after;
  266. #endif /* MTAB_LOCKING */
  267.  
  268.     if (mnt_file) {
  269. #ifdef DEBUG
  270.         dlog("Forced close on %s in read_mtab", mtab);
  271. #endif /* DEBUG */
  272.         endmntent(mnt_file);
  273.         mnt_file = 0;
  274.     }
  275.  
  276. #ifdef MTAB_LOCKING
  277. again:
  278.     if (mfp) {
  279.         endmntent(mfp);
  280.         mfp = 0;
  281.     }
  282.  
  283.     clock_valid = 0;
  284.     if (stat(mtab, &st_before) < 0) {
  285.         plog(XLOG_ERROR, "%s: stat: %m", mtab);
  286.         if (errno == ESTALE) {
  287.             /* happens occasionally */
  288.             sleep(1);
  289.             goto again;
  290.         }
  291.         return 0;
  292.     }
  293. #endif /* MTAB_LOCKING */
  294. #endif /* UPDATE_MTAB */
  295.  
  296. eacces:
  297.     mfp = setmntent(mtab, "r+");
  298.     if (!mfp) {
  299.         /*
  300.          * Since setmntent locks the descriptor, it
  301.          * is possible it can fail... so retry if
  302.          * needed.
  303.          */
  304.         if (errno == EACCES || errno == EAGAIN) {
  305. #ifdef DEBUG
  306.             dlog("Blocked, trying to obtain exclusive mtab lock");
  307. #endif /* DEBUG */
  308.             goto eacces;
  309.         } else if (errno == ENFILE && retries++ < NFILE_RETRIES) {
  310.             sleep(1);
  311.             goto eacces;
  312.         }
  313.  
  314.         plog(XLOG_ERROR, "setmntent(\"%s\", \"r+\"): %m", mtab);
  315.         return 0;
  316.     }
  317.  
  318. #ifdef MTAB_LOCKING
  319. #ifdef UPDATE_MTAB
  320.     /*
  321.      * At this point we have an exclusive lock on the mount list,
  322.      * but it may be the wrong one so...
  323.      */
  324.  
  325.     /*
  326.      * Need to get an exclusive lock on the current
  327.      * mount table until we have a new copy written
  328.      * out, when the lock is released in free_mntlist.
  329.      * flock is good enough since the mount table is
  330.      * not shared between machines.
  331.      */
  332.     do
  333.         rc = lock(fileno(mfp));
  334.     while (rc < 0 && errno == EINTR);
  335.     if (rc < 0) {
  336.         plog(XLOG_ERROR, "Couldn't lock %s: %m", mtab);
  337.         endmntent(mfp);
  338.         return 0;
  339.     }
  340.     /*
  341.      * Now check whether the mtab file has changed under our feet
  342.      */
  343.     if (stat(mtab, &st_after) < 0) {
  344.         plog(XLOG_ERROR, "%s: stat", mtab);
  345.         goto again;
  346.     }
  347.  
  348.     if (st_before.st_dev != st_after.st_dev ||
  349.         st_before.st_ino != st_after.st_ino) {
  350.             if (racing == 0) {
  351.                 /* Sometimes print a warning */
  352.                 plog(XLOG_WARNING,
  353.                     "Possible mount table race - retrying %s", fs);
  354.             }
  355.             racing = (racing+1) & 3;
  356.             goto again;
  357.     }
  358. #endif /* UPDATE_MTAB */
  359. #endif /* MTAB_LOCKING */
  360.  
  361.     mpp = &mhp;
  362.  
  363. /*
  364.  * XXX - In SunOS 4 there is (yet another) memory leak
  365.  * which loses 1K the first time getmntent is called.
  366.  * (jsp)
  367.  */
  368.     while (mep = getmntent(mfp)) {
  369.         /*
  370.          * Allocate a new slot
  371.          */
  372.         *mpp = ALLOC(mntlist);
  373.  
  374.         /*
  375.          * Copy the data returned by getmntent
  376.          */
  377.         (*mpp)->mnt = mnt_dup(mep);
  378.  
  379.         /*
  380.          * Move to next pointer
  381.          */
  382.         mpp = &(*mpp)->mnext;
  383.     }
  384.     *mpp = 0;
  385.  
  386. #ifdef UPDATE_MTAB
  387.     /*
  388.      * If we are not updating the mount table then we
  389.      * can free the resources held here, otherwise they
  390.      * must be held until the mount table update is complete
  391.      */
  392.     mnt_file = mfp;
  393. #else
  394.     endmntent(mfp);
  395. #endif /* UPDATE_MTAB */
  396.  
  397.     return mhp;
  398. }
  399.  
  400. #endif /* READ_MTAB_FROM_FILE */
  401.